package com.text.jwt.config;

import com.auth0.jwt.JWT;
import com.text.jwt.entities.Vo.AuthorizeVo;
import com.text.jwt.entities.dto.Account;
import com.text.jwt.filter.JwtAuthorizeFilter;
import com.text.jwt.resp.ResultData;
import com.text.jwt.resp.ReturnCodeEnum;
import com.text.jwt.services.AccountService;
import com.text.jwt.utils.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;
import java.io.PrintWriter;

@Configuration
public class SecurityConfiguration {

    @Resource
    private JwtUtils jwtUtils;
    @Resource
    private JwtAuthorizeFilter jwtAuthorizeFilter;

    @Resource
    private AccountService accountService;

    // 配置 security
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                // 配置Http请求权限
                .authorizeHttpRequests(conf -> conf
                        // 允许所有请求访问/api/auth/**路径
                        .requestMatchers("/api/auth/**").permitAll()
                        // 所有请求都需要认证
                        .anyRequest().authenticated()
                )
                // 配置登录功能
                .formLogin(conf -> conf
                        // 登录成功后跳转到/api/auth/login处理
                        .loginProcessingUrl("/api/auth/login")
                        // 登录失败后调用onAuthenticationFailure方法
                        .failureHandler(this::onAuthenticationFailure)
                        // 登录成功后调用onAuthenticationSuccess方法
                        .successHandler(this::onAuthenticationSuccess)
                )
                // 配置注销功能
                .logout(conf -> conf
                        // 跳转到/api/auth/logout进行注销
                        .logoutUrl("/api/auth/logout")
                        // 注销成功后调用onLogoutSuccess方法
                        .logoutSuccessHandler(this::onLogoutSuccess)
                )
                // 禁用CSRF
                .csrf(AbstractHttpConfigurer::disable)
                .exceptionHandling(conf -> conf
                        .authenticationEntryPoint(this::onUnauthorized)
                        .accessDeniedHandler(this::onAccessDeny)
                )
                // 配置session管理，使用无状态模式
                .sessionManagement(conf -> conf
                        // 无状态模式
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 添加过滤器，验证 jwt 是否正确
                .addFilterBefore(jwtAuthorizeFilter, UsernamePasswordAuthenticationFilter.class)
                // 构建配置
                .build();
    }

    public void onUnauthorized(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException exception
    ) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        String code = ReturnCodeEnum.RC401.getCode();
        String message = "用户权限不足";
        response.getWriter().write(ResultData.fail(code, message).asJsonString());
    }

    public void onAccessDeny(
            HttpServletRequest request,
            HttpServletResponse response,
            AccessDeniedException accessDeniedException
    ) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        String code = ReturnCodeEnum.RC403.getCode();
        String message = ReturnCodeEnum.RC403.getMessage();
        response.getWriter().write(ResultData.fail(code, message).asJsonString());
    }

    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication
    ) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        // 登录成功后 才会颁发jwt令牌 我们先拿到登录的用户信息
        User user = (User) authentication.getPrincipal();
        // system.out.println(principal); 通过打印可以发现 这个类里面包含了很多东西
        Account account = accountService.findAccountByName(user.getUsername());
        String token = jwtUtils.createJwt(user, account.getId(), account.getUsername());
        AuthorizeVo vo = new AuthorizeVo();
        vo.setExpire(JWT.decode(token).getExpiresAt());
        vo.setRole(account.getRole());
        vo.setToken(token);
        vo.setUsername(account.getUsername());
        System.out.println("Vo类型" + vo);
        response.getWriter().write(ResultData.success(vo).asJsonString());
    }

    public void onAuthenticationFailure(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException exception
    ) throws IOException, ServletException, UsernameNotFoundException {
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(ResultData.fail(ReturnCodeEnum.RC401.getCode(), exception.getMessage() ).asJsonString());
    }

    public void onLogoutSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication
    ) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        String authorization = request.getHeader("Authorization");
        System.out.println("dang" + authorization);
        if (jwtUtils.invalidateJwt(authorization)) {
            writer.write(ResultData.success("退出登录").asJsonString());
        } else {
            writer.write(ResultData.fail("400", "退出登录失败").asJsonString());
        }
    }
}
